////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                            //
//                                                         WNProject                                                          //
//                                                                                                                            //
//            This file is distributed under the BSD 2-Clause open source license. See License.txt for details.               //
//                                                                                                                            //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef __WN_CONCURRENCY_CRITICAL_SECTION_H__
#define __WN_CONCURRENCY_CRITICAL_SECTION_H__

#include "WNCore/inc/WNPlatform.h"
#include "WNCore/inc/WNTypes.h"
#include "WNCore/inc/WNMacros.h"

#ifdef _WN_WINDOWS
    #include <windows.h>
#elif defined _WN_LINUX
    #include <pthread.h>
    #include <unistd.h>
#endif

namespace WNConcurrency {
    class WNCriticalSection {
    public:
        WN_INLINE WNCriticalSection(WN_UINT32 _spinCount = 0);
        WN_INLINE ~WNCriticalSection();

        WN_INLINE WN_VOID Lock();
        WN_INLINE WN_BOOL TryLock();
        WN_INLINE WN_VOID Unlock();

        WN_INLINE WN_UINT32 SetSpinCount(WN_UINT32 _spinCount);

    private:
        #ifdef _WN_WINDOWS
            CRITICAL_SECTION mCriticalSection;
        #elif defined _WN_LINUX
            pid_t mOwningThread;
            pthread_mutex_t mMutex;
            WN_ATOM_T mLockCount;
            WN_UINT32 mRecursionCount;
            WN_ATOM_T mSpinCount;
        #endif
    };

    class WNCriticalSectionScopeLock {
    public:
        WN_INLINE WNCriticalSectionScopeLock(WNCriticalSection& _criticalSection);
        WN_INLINE ~WNCriticalSectionScopeLock();

    private:
        WNCriticalSection& mCriticalSection;

        WN_BOOL mLocked;
    };
}

#define WN_CRITICAL_SECTION_SCOPE_LOCK(_criticalSection) WNCriticalSectionScopeLock WN_UNIQUE_VARIABLE(criticalSection)(_criticalSection)

#include "WNConcurrency/inc/WNCriticalSection.inl"

#endif // __WN_CONCURRENCY_CRITICAL_SECTION_H__
